﻿Imports System.Diagnostics.CodeAnalysis

Public Module MRUConvert

#Region "ToNullable Method(s)"

    ''' <summary>
    ''' Gets the object to convert.
    ''' </summary>
    ''' <param name="oVal">val</param>
    ''' <returns></returns>
    <SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")>
    Private Function GetObjectToConvert(oVal As Object) As Object
        If (oVal Is Nothing) OrElse (oVal Is DBNull.Value) Then
            Return Nothing
        End If

        Dim dataParameter = TryCast(oVal, IDataParameter)
        If (dataParameter IsNot Nothing) Then
            Dim oTemp As Object = dataParameter.Value

            If (oTemp Is Nothing) OrElse (oTemp Is DBNull.Value) Then
                Return Nothing
            End If

            Return oTemp
        End If

        Return oVal
    End Function

#Region "ToNullableBoolean Method(s)"

    ''' <summary>
    ''' Converts a value to a timestamp value.  
    ''' Null, DBNull, and non boolean values are converted to null. 
    ''' See ToNullableBoolean(Object oVal, bool bThrowErrors) for complete rules.
    ''' </summary>
    ''' <param name="oVal">Value to convert</param>
    ''' <returns>The value.</returns>
    Public Function ToNullableBoolean(oVal As Object) As Nullable(Of Boolean)
        Return ToNullableBoolean(oVal, False)
    End Function

    ''' <summary>
    ''' Converts a value to a boolean value.  
    ''' Null and DBNull values are converted to null.  The conversion rules are as follows:
    '''     Type    Value    Output
    '''     String  "true"   true
    '''     String  "false"  false
    '''     String  Number   true if != 0, false if == 0.
    '''     String  other    null or error
    '''     Numeric 0        false
    '''     Numeric != 0     true
    '''     DateTime         null or error
    '''     other            Depends upon result of System.Convert.ToBoolean().
    ''' </summary>        
    ''' <param name="oVal">Value to convert</param>
    ''' <param name="bThrowErrors">If true then conversion errors produce exceptions.  Otherwise they are converted to null.</param>
    ''' <returns>The value.</returns>
    Public Function ToNullableBoolean(oVal As Object, bThrowErrors As Boolean) As Nullable(Of Boolean)
        Dim oTemp As Object = GetObjectToConvert(oVal)

        If oTemp Is Nothing Then
            Return Nothing
        End If

        If TypeOf oTemp Is Boolean Then
            Return CBool(oTemp)
        End If
        Dim szVal As String = TryCast(oTemp, String)
        If szVal IsNot Nothing Then
            If IsNumeric(szVal) Then
                Return Convert.ToBoolean(Convert.ToDouble(szVal))
            End If

            szVal = szVal.ToUpper().Trim()
            If szVal = "Y" Then
                Return True
            End If
            If szVal = "N" Then
                Return False
            End If
        End If
        Try
            Return Convert.ToBoolean(oTemp)
        Catch
            If False = bThrowErrors Then
                Return Nothing
            End If
            Throw
        End Try
    End Function

    ''' <summary>
    ''' Converts a string value to boolean. 
    ''' </summary>
    ''' <param name="oVal"></param>
    ''' <param name="szTrueValue"></param>
    ''' <param name="szFalseValue"></param>
    ''' <returns></returns>
    Public Function ToNullableBoolean(oVal As Object, szTrueValue As String, szFalseValue As String) As Nullable(Of Boolean)
        Dim oTemp As Object = GetObjectToConvert(oVal)

        If oTemp Is Nothing Then
            Return Nothing
        End If

        If TypeOf oTemp Is Boolean Then
            Return CBool(oTemp)
        End If
        Dim szVal As String = oTemp.ToString()
        Return ToNullableBoolean(szVal, szTrueValue, szFalseValue)
    End Function

    ''' <summary>
    ''' Toes the boolean.
    ''' </summary>
    ''' <param name="szVal">The sz val.</param>
    ''' <param name="szTrueValue">The sz true value.</param>
    ''' <param name="szFalseValue">The sz false value.</param>
    ''' <returns></returns>
    Public Function ToNullableBoolean(szVal As String, szTrueValue As String, szFalseValue As String) As Nullable(Of Boolean)
        If szVal Is Nothing Then
            Return Nothing
        End If
        szVal = szVal.Trim()
        If 0 = String.Compare(szVal, szTrueValue, True) Then
            Return True
        End If
        If 0 = String.Compare(szVal, szFalseValue, True) Then
            Return False
        End If
        Return Nothing
    End Function

#End Region

#Region "ToNullableDateTime Method(s)"

    ''' <summary>
    ''' Converts a value to a timestamp value.  
    ''' Null, DBNull, and non DateTime values are converted to null. 
    ''' </summary>
    ''' <param name="oVal">Value to convert</param>
    ''' <returns>The value.</returns>
    Public Function ToNullableDateTime(oVal As Object) As Nullable(Of DateTime)
        Return ToNullableDateTime(oVal, False)
    End Function

    ''' <summary>
    ''' Converts a value to a timestamp value.  
    ''' Null and DBNull values are converted to null.
    ''' </summary>
    ''' <param name="oVal">Value to convert</param>
    ''' <param name="bThrowErrors">If true then conversion errors produce exceptions.  Otherwise they are converted to null.</param>
    ''' <returns>The value.</returns>
    Public Function ToNullableDateTime(oVal As Object, bThrowErrors As Boolean) As Nullable(Of DateTime)
        Dim oTemp As Object = GetObjectToConvert(oVal)

        If oTemp Is Nothing Then
            Return Nothing
        End If

        If TypeOf oTemp Is DateTime Then
            Return DirectCast(oTemp, DateTime)
        End If
        Try
            Return Convert.ToDateTime(oTemp)
        Catch
            If False = bThrowErrors Then
                Return Nothing
            End If
            Throw
        End Try
    End Function

#End Region

#Region "ToNullableDateTimeDate Method(s)"

    ''' <summary>
    ''' Converts a value to a date value with midnight for the time.  
    ''' Null, DBNull, and non DateTime values are converted to null. 
    ''' </summary>
    ''' <param name="oVal">Value to convert</param>
    ''' <returns>The value.</returns>
    Public Function ToNullableDateTimeDate(oVal As Object) As Nullable(Of DateTime)
        Return ToNullableDateTimeDate(oVal, False)
    End Function

    ''' <summary>
    ''' Converts a value to a date value with midnight for the time.  
    ''' Null and DBNull values are converted to null.
    ''' </summary>
    ''' <param name="oVal">Value to convert</param>
    ''' <param name="bThrowErrors">If true then conversion errors produce exceptions.  Otherwise they are converted to null.</param>
    ''' <returns>The value.</returns>
    Public Function ToNullableDateTimeDate(oVal As Object, bThrowErrors As Boolean) As Nullable(Of DateTime)
        Dim oTemp As Object = GetObjectToConvert(oVal)

        If oTemp Is Nothing Then
            Return Nothing
        End If

        If TypeOf oTemp Is DateTime Then
            Return DirectCast(oTemp, DateTime).[Date]
        End If
        Try
            Return Convert.ToDateTime(oTemp).[Date]
        Catch
            If False = bThrowErrors Then
                Return Nothing
            End If
            Throw
        End Try
    End Function

#End Region

#Region "ToNullableDecimal Method(s)"

    ''' <summary>
    ''' Converts a value to a decimal number.  
    ''' Null and DBNull values are converted to null.
    ''' </summary>
    ''' <param name="oVal">Value to convert</param>
    ''' <param name="bThrowErrors">If true then conversion errors produce exceptions.  Otherwise they are converted to null.</param>
    ''' <returns>The value.</returns>
    Public Function ToNullableDecimal(oVal As Object, bThrowErrors As Boolean) As Nullable(Of Decimal)
        Dim oTemp As Object = GetObjectToConvert(oVal)

        If oTemp Is Nothing Then
            Return Nothing
        End If

        If TypeOf oTemp Is Decimal Then
            Return CDec(oTemp)
        End If
        Try
            Return Convert.ToDecimal(oTemp)
        Catch
            Try
                'To decimal fails if we have a currency symbol.  Remove it and try again.
                Dim szVal As String = oVal.ToString().TrimStart()
                If szVal(0) = "$"c Then
                    szVal = szVal.Remove(0, 1)
                    Return Convert.ToDecimal(szVal)
                ElseIf szVal(0) = "-"c AndAlso szVal(1) = "$"c Then
                    szVal = szVal.Remove(1, 1)
                    Return Convert.ToDecimal(szVal)
                End If
            Catch
            End Try
            If False = bThrowErrors Then
                Return Nothing
            End If
            Throw
        End Try
    End Function

    ''' <summary>
    ''' Converts a value to a decimal number.  
    ''' Null, DBNull, and non numeric values are converted to null. 
    ''' </summary>
    ''' <param name="oVal">Value to convert</param>
    ''' <returns>The value.</returns>
    Public Function ToNullableDecimal(oVal As Object) As Nullable(Of Decimal)
        Return ToNullableDecimal(oVal, False)
    End Function

#End Region

#Region "ToNullableDouble Method(s)"

    ''' <summary>
    ''' Converts a value to a double precision floating point number.  
    ''' Null, DBNull, and non numeric values are converted to null. 
    ''' </summary>
    ''' <param name="oVal">Value to convert</param>
    ''' <returns>The value.</returns>
    Public Function ToNullableDouble(oVal As Object) As Nullable(Of Double)
        Return ToNullableDouble(oVal, False)
    End Function

    ''' <summary>
    ''' Converts a value to a double precision floating point number.  
    ''' Null and DBNull values are converted to null.
    ''' </summary>
    ''' <param name="oVal">Value to convert</param>
    ''' <param name="bThrowErrors">If true then conversion errors produce exceptions.  Otherwise they are converted to null.</param>
    ''' <returns>The value.</returns>
    Public Function ToNullableDouble(oVal As Object, bThrowErrors As Boolean) As Nullable(Of Double)
        Dim oTemp As Object = GetObjectToConvert(oVal)

        If oTemp Is Nothing Then
            Return Nothing
        End If

        If TypeOf oTemp Is Double Then
            Return CDbl(oTemp)
        End If
        Try
            Return Convert.ToDouble(oTemp)
        Catch
            If False = bThrowErrors Then
                Return Nothing
            End If
            Throw
        End Try
    End Function

#End Region

#Region "ToNullableIntShort Method(s)"

    ''' <summary>
    ''' Converts a value to a 16 bit integer.  Floating point numbers are truncated.
    ''' Null and DBNull values are converted to null.
    ''' </summary>
    ''' <param name="oVal">Value to convert</param>
    ''' <param name="bThrowErrors">If true then conversion errors produce exceptions.  Otherwise they are converted to null.</param>
    ''' <returns>The value.</returns>
    Public Function ToNullableIntShort(oVal As Object, bThrowErrors As Boolean) As Nullable(Of Short)
        Dim oTemp As Object = GetObjectToConvert(oVal)

        If oTemp Is Nothing Then
            Return Nothing
        End If

        If TypeOf oTemp Is Int16 Then
            Return DirectCast(oTemp, Int16)
        End If
        Try
            'Convert.ToInt16 has an issue when called on strings that contain an embedded decimal point.
            'Convert a string to a decimal then an int.  *Note this drops the decimal value.
            If TypeOf oTemp Is String Then
                Return Convert.ToDecimal(oTemp)
            End If
            Return Convert.ToInt16(oTemp)
        Catch
            If False = bThrowErrors Then
                Return Nothing
            End If
            Throw
        End Try
    End Function

    ''' <summary>
    ''' Converts a value to a 16 bit integer.  Floating point numbers are truncated.
    ''' Null, DBNull, and non numeric values are converted to null. 
    ''' </summary>
    ''' <param name="oVal">Value to convert</param>
    ''' <returns>The value.</returns>
    Public Function ToNullableIntShort(oVal As Object) As Nullable(Of Short)
        Return ToNullableIntShort(oVal, False)
    End Function

#End Region

#Region "ToNullableInt Method(s)"

    ''' <summary>
    ''' Converts a value to a 32 bit integer.  Floating point numbers are truncated.
    ''' Null and DBNull values are converted to null.
    ''' </summary>
    ''' <param name="oVal">Value to convert</param>
    ''' <param name="bThrowErrors">If true then conversion errors produce exceptions.  Otherwise they are converted to null.</param>
    ''' <returns>The value.</returns>
    Public Function ToNullableInt(oVal As Object, bThrowErrors As Boolean) As Nullable(Of Integer)
        Dim oTemp As Object = GetObjectToConvert(oVal)

        If oTemp Is Nothing Then
            Return Nothing
        End If

        If TypeOf oTemp Is Integer Then
            Return CInt(oTemp)
        End If
        Try
            'Convert.ToInt32 has an issue when called on strings that contain an embedded decimal point.
            'Convert a string to a decimal then an int.  *Note this drops the decimal value.
            If TypeOf oTemp Is String Then
                Return CInt(Convert.ToDecimal(oTemp))
            End If
            Return Convert.ToInt32(oTemp)
        Catch
            If False = bThrowErrors Then
                Return Nothing
            End If
            Throw
        End Try
    End Function

    ''' <summary>
    ''' Converts a value to a 32 bit integer.  Floating point numbers are truncated.
    ''' Null, DBNull, and non numeric values are converted to null. 
    ''' </summary>
    ''' <param name="oVal">Value to convert</param>
    ''' <returns>The value.</returns>
    Public Function ToNullableInt(oVal As Object) As Nullable(Of Integer)
        Return ToNullableInt(oVal, False)
    End Function

#End Region

#Region "ToNullableLong Method(s)"

    ''' <summary>
    ''' Converts a value to a 64 bit integer.  Floating point numbers are truncated.
    ''' Null and DBNull values are converted to null.
    ''' </summary>
    ''' <param name="oVal">Value to convert</param>
    ''' <param name="bThrowErrors">If true then conversion errors produce exceptions.  Otherwise they are converted to null.</param>
    ''' <returns>The value.</returns>
    Public Function ToNullableLong(oVal As Object, bThrowErrors As Boolean) As Nullable(Of Long)
        Dim oTemp As Object = GetObjectToConvert(oVal)

        If oTemp Is Nothing Then
            Return Nothing
        End If

        If TypeOf oTemp Is Int64 Then
            Return DirectCast(oTemp, Int64)
        End If
        Try
            'Convert.ToInt64 has an issue when called on strings that contain an embedded decimal point.
            'Convert a string to a decimal then an int.  *Note this drops the decimal value.
            If TypeOf oTemp Is String Then
                Return Convert.ToDecimal(oTemp)
            End If
            Return Convert.ToInt64(oTemp)
        Catch
            If False = bThrowErrors Then
                Return Nothing
            End If
            Throw
        End Try
    End Function

    ''' <summary>
    ''' Converts a value to a 64 bit integer.  Floating point numbers are truncated.
    ''' Null, DBNull, and non numeric values are converted to null. 
    ''' </summary>
    ''' <param name="oVal">Value to convert</param>
    ''' <returns>The value.</returns>
    Public Function ToNullableLong(oVal As Object) As Nullable(Of Long)
        Return ToNullableLong(oVal, False)
    End Function

#End Region

#End Region

    Private Function IsNumeric(szVal As String) As Boolean
        Dim dOut As Double
        Return Double.TryParse(szVal, dOut)
    End Function
End Module
